如何使用 React 开发者工具调试 React 组件 您所在的位置:网站首页 label htmlfor 如何使用 React 开发者工具调试 React 组件

如何使用 React 开发者工具调试 React 组件

#如何使用 React 开发者工具调试 React 组件| 来源: 网络整理| 查看: 265

作者选择Creative Commons作为Write for DOnations计划的一部分接受捐赠。

简介

由于 React 应用程序可以快速扩展和增长,因此细微的错误很容易渗透到您的代码中。React Developer Tools 浏览器扩展可以通过让您更深入地了解每个组件的当前状态来帮助您追踪这些错误。 React Developer Tools 为您提供了一个界面,用于探索 React 组件树以及单个组件的当前道具、状态和上下文。 React Developer Tools 还可以让您确定哪些组件正在重新渲染,并且可以生成图表来显示各个组件需要多长时间来渲染。您可以使用此信息来追踪低效代码或优化数据密集型组件。

本教程首先安装 React Developer Tools 浏览器扩展。然后,您将构建一个文本分析器作为测试应用程序,它将获取一段文本并显示诸如字数、字符数和字符用法等信息。最后,您将使用 React 开发人员工具来探索文本分析器的组件并跟踪不断变化的道具和上下文。示例将使用Chrome 浏览器,但您也可以使用Firefox的插件。

在本教程结束时,您将能够开始使用 React 开发人员工具来调试和探索任何 React 项目。

先决条件

要使用 Chrome React Developer Tools 扩展,您需要下载并安装Google Chrome 网络浏览器或开源Chromium 网络浏览器。您还可以将React Developer Tools FireFox 插件用于FireFox Web 浏览器。

您将需要一个运行Node.js的开发环境;本教程在 Node.js 版本 10.22.0 和 npm 版本 6.14.6 上进行了测试。要在 macOS 或 Ubuntu 18.04 上安装它,请按照How to Install Node.js and Create a Local Development Environment on macOS或How To Install Node.js on 的 Installing Using a PPA 部分中的步骤操作Ubuntu 18.04。

使用创建 React App设置的 React 开发环境。要进行此设置,请遵循如何管理 React 类组件上的状态教程](https://www.digitalocean.com/community/tutorials/how-to-manage-state-on-react-class-components#step-1-%E2%80%94-creating-an-empty-project)的[步骤 1 — 创建一个空项目,这将删除非必要的样板。本教程将使用debug-tutorial作为项目名称。

您将在本教程中使用 React 组件和 Hook,包括useState和上下文 Hook。您可以在我们的教程如何在 React 中创建自定义组件、如何使用 React 组件上的 Hook 管理状态和如何在具有上下文的 React 组件之间共享状态中了解组件和 Hooks。

您还需要 JavaScript 和 HTML 的基本知识,您可以在我们的如何使用 HTML 系列和如何使用 JavaScript 编码中找到这些知识。 CSS 的基本知识也会很有用,您可以在Mozilla Developer Network找到这些知识。

第 1 步 - 安装 React 开发者工具扩展

在这一步中,您将在 Chrome 中安装 React Developer Tools 浏览器扩展。您将使用 ChromeJavaScript 控制台中的开发人员工具来探索您在先决条件中创建的debug-tutorial项目的组件树。此步骤将使用 Chrome,但在 Firefox 中将 React 开发人员工具安装为附加组件的步骤几乎相同。

在这一步结束时,您将在浏览器中安装 React 开发人员工具,并且您将能够按名称浏览和过滤组件。

React 开发者工具是 Chrome 和 Firefox 浏览器的插件。添加扩展时,您正在向开发人员控制台添加其他工具。访问Chrome 插件页面以获取 React Developer Tools 以安装扩展。

单击添加到 Chrome 按钮。然后点击 Add extension 按钮确认:

Chrome 添加扩展按钮

Chrome 将安装扩展程序,成功消息和新图标将出现在浏览器右上角地址栏旁边:

Chrome 成功消息

如果图标没有出现,你可以通过点击拼图来添加它,然后点击 React Developer Tools 的图钉图标:

引脚扩展

当您在没有任何 React 组件的页面上时,该图标将显示为灰色。但是,如果您在带有 React 组件的页面上,该图标将显示为蓝色和绿色。如果单击该图标,它将指示该应用程序正在运行 React 的生产版本。

访问digitalocean.com,发现首页运行的是生产版的 React:

DigitalOcean React 生产构建信息

现在您在使用 React 的网站上,打开控制台以访问 React 开发人员工具。通过右键单击并检查元素或通过单击 View > Developer > JavaScript console 打开工具栏来打开控制台。

打开控制台时,您会发现两个新选项卡:Components 和 Profiler:

控制台打开

Components 选项卡将显示当前的 React 组件树,以及任何道具、状态或上下文。 Profiler 选项卡可让您记录交互并测量组件渲染。您将在第 3 步中探索 Profiler 选项卡。

单击 Components 选项卡以查看当前的组件树。

由于这是一个生产版本,代码将是minified并且组件没有描述性名称:

控制台中 digitalocean.com 的组件

现在您已经在一个工作网站上试用了 React Developer Tools,您可以在您的测试应用程序中使用它。如果您还没有启动debug-tutorial应用程序,请转到终端窗口并从项目的根目录运行npm start。

打开浏览器到http://localhost:3000。

请注意,React Developer Tools 的图标现在是红色和白色的。如果你点击 React Developer Tools 图标,你会看到页面处于开发模式的警告。由于您仍在处理示例应用程序,因此这是意料之中的。

打开控制台,您会在 Components 选项卡中找到App组件的名称。

基础组件

目前还没有很多信息,但是当您在下一步构建项目时,您会看到所有组件形成一个可导航的树。

在这一步中,您将 React Developer Tools 扩展添加到 Chrome。您在生产和开发页面上都激活了这些工具,并在 Components 选项卡中简要探索了您的debug-tutorial项目。在下一步中,您将构建文本分析器,您将使用它来试用 React 开发人员工具的功能。

第 2 步 - 识别实时组件道具和上下文

在这一步中,您将构建一个小型应用程序来分析一段文本。该应用程序将确定并报告输入字段中文本的字数、字符数和字符频率。在构建应用程序时,您将使用 React Developer Tools 来探索每个组件的当前状态和 props。您还将使用 React 开发人员工具来查看深度嵌套组件中的当前上下文。最后,您将使用这些工具来识别在状态更改时重新渲染的组件。

在这一步结束时,您将能够使用 React 开发人员工具来探索实时应用程序并观察当前的道具和状态,而无需控制台语句或调试器。

首先,您将创建一个需要大量文本的输入组件。

打开App.js文件:

nano src/components/App/App.js

在组件内部,添加一个div和一个类wrapper,然后创建一个元素围绕一个元素:

调试教程/src/components/App/App.js

import React from 'react'; import './App.css'; function App() { return( Add Your Text Here: ) } export default App;

这将是您的用户的输入区域。htmlFor属性使用JSX将label元素链接到id的text元素。您还为组件提供了10行和100列,以便为大量文本提供空间。

保存并关闭文件。接下来打开App.css:

nano src/components/App/App.css

通过将内容替换为以下内容,为应用程序添加一些样式:

调试教程/src/components/App.App.css

.wrapper { padding: 20px; } .wrapper button { background: none; border: black solid 1px; cursor: pointer; margin-right: 10px; } .wrapper div { margin: 20px 0; }

在这里,您向wrapper类添加一些填充,然后通过删除背景颜色并添加一些边距来简化子元素。最后,为子元素添加一个小边距。这些样式将应用于您将构建的组件以显示有关文本的信息。

保存文件。当你这样做时,浏览器将刷新,你会看到输入:

文本区域

打开App.js:

nano src/components/App/App.js

接下来,创建一个上下文来保存来自元素的值。使用useStateHook捕获数据:

调试教程/src/components/App/App.js

import React, { createContext, useState } from 'react'; import './App.css'; export const TextContext = createContext(); function App() { const [text, setText] = useState(''); return( Add Your Text Here: setText(e.target.value)} > ) } export default App;

确保导出TextContext,然后用TextContext.Provider包装整个组件。通过将onChange属性添加到元素来捕获数据。

保存文件。浏览器将重新加载。确保你打开了 React Developer Tools,并注意到App组件现在将Context.Provider显示为子组件。

React 开发者工具中的组件上下文

默认情况下,组件有一个通用名称 -Context- 但您可以通过将displayName属性添加到生成的上下文来更改它。在App.js中,添加一行,将displayName设置为TextContext:

调试教程/src/components/App/App.js

import React, { createContext, useState } from 'react'; import './App.css'; export const TextContext = createContext(); TextContext.displayName = 'TextContext'; function App() { ... } export default App;

没有必要添加displayName,但它确实有助于在控制台中分析组件树时导航组件。您还将在侧栏中看到useStateHook 的值。在输入中键入一些文本,您将在 React Developer Tools 中的App组件的 hooks 部分下看到更新的值。

更新开发者工具中的值

Hook 也有一个通用名称State,但这并不像上下文那样容易更新。有一个useDebugValueHook,但它只适用于自定义 Hook,并不推荐用于所有自定义 Hook。

在这种情况下,App组件的 state 是TextContext.Provider的 prop。在 React Developer Tools 中单击TextContext.Provider,您会看到value也反映了您使用 state 设置的输入值:

上下文的更新值

React 开发者工具向你展示了实时的 prop 和上下文信息,并且随着你添加组件,价值会增长。

接下来,添加一个名为TextInformation的组件。该组件将是具有特定数据分析的组件的容器,例如字数。

首先,制作目录:

mkdir src/components/TextInformation

然后在文本编辑器中打开TextInformation.js。

nano src/components/TextInformation/TextInformation.js

在组件内部,您将拥有三个独立的组件:CharacterCount、WordCount和CharacterMap。稍后您将制作这些组件。

TextInformation组件将使用useReducerHook 来切换每个组件的显示。创建一个reducer函数来切换每个组件的显示值,并创建一个按钮来使用onClick操作来切换每个组件:

调试教程/src/components/TextInformation/TextInformation.js

import React, { useReducer } from 'react'; const reducer = (state, action) => { return { ...state, [action]: !state[action] } } export default function TextInformation() { const [tabs, toggleTabs] = useReducer(reducer, { characterCount: true, wordCount: true, characterMap: true }); return( toggleTabs('characterCount')}>Character Count toggleTabs('wordCount')}>Word Count toggleTabs('characterMap')}>Character Map ) }

请注意,您的useReducerHook 以一个将每个键映射到布尔值的对象开始。 reducer 函数使用扩展运算符来保留以前的值,同时使用action参数设置新值。

保存并关闭文件。然后打开App.js:

nano src/components/App/App.js

添加新组件:

调试教程/src/components/App/App.js

import React, { createContext, useState } from 'react'; import './App.css'; import TextInformation from '../TextInformation/TextInformation'; ... function App() { const [text, setText] = useState(''); return( Add Your Text Here: setText(e.target.value)} > ) } export default App;

保存并关闭文件。当您这样做时,浏览器将重新加载,您将看到更新后的组件。如果你在 React Developer Tools 中点击TextInformation,你会看到每次点击按钮的值都会更新:

点击时更新减速器

现在您已经有了容器组件,您需要创建每个信息组件。每个组件都会接受一个名为show的 prop。如果show为假,则组件将返回null。组件将消耗TextContext,分析数据并显示结果。

首先,创建CharacterCount组件。

首先,新建一个目录:

mkdir src/components/CharacterCount

然后,在文本编辑器中打开CharacterCount.js:

nano src/components/CharacterCount/CharacterCount.js

在组件内部,创建一个使用show属性的函数,如果show为假,则显示null:

调试教程/src/components/CharacterCount/CharacterCount.js

import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { TextContext } from '../App/App'; export default function CharacterCount({ show }) { const text = useContext(TextContext); if(!show) { return null; } return( Character Count: {text.length} ) } CharacterCount.proTypes = { show: PropTypes.bool.isRequired }

在CharacterCount函数中,您使用useContextHook 将TextContext的值分配给一个变量。然后,您返回一个,它使用length方法显示字符数。最后,PropTypes添加了一个弱类型系统来提供一些强制措施,以确保不会传递错误的道具类型。

保存并关闭文件。打开TextInformation.js:

nano src/components/TextInformation/TextInformation.js

导入CharacterCount并在按钮后添加组件,将tabs.characterCount作为show属性传递:

调试教程/src/components/TextInformation/TextInformation.js

import React, { useReducer } from 'react'; import CharacterCount from '../CharacterCount/CharacterCount'; const reducer = (state, action) => { return { ...state, [action]: !state[action] } } export default function TextInformation() { const [tabs, toggleTabs] = useReducer(reducer, { characterCount: true, wordCount: true, characterMap: true }); return( toggleTabs('characterCount')}>Character Count toggleTabs('wordCount')}>Word Count toggleTabs('characterMap')}>Character Map ) }

保存文件。浏览器将重新加载,您将在 React 开发人员工具中看到该组件。请注意,当您在输入中添加单词时,上下文将更新。如果你切换组件,你会在每次点击后看到 props 更新:

添加文本和切换

您还可以通过单击属性并更新值来手动添加或更改道具:

手动更换道具

接下来,添加一个WordCount组件。

创建目录:

mkdir src/components/WordCount

在文本编辑器中打开文件:

nano src/components/WordCount/WordCount.js

制作一个类似于CharacterCount的组件,但在显示长度之前,对空格使用split方法创建一个单词数组:

调试教程/src/components/WordCount/WordCount.js

import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { TextContext } from '../App/App'; export default function WordCount({ show }) { const text = useContext(TextContext); if(!show) { return null; } return( Word Count: {text.split(' ').length} ) } WordCount.proTypes = { show: PropTypes.bool.isRequired }

保存并关闭文件。

最后,创建一个CharacterMap组件。该组件将显示特定字符在文本块中的使用频率。然后它将按文章中的频率对字符进行排序并显示结果。

首先,制作目录:

mkdir src/components/CharacterMap

接下来,在文本编辑器中打开CharacterMap.js:

nano src/components/CharacterMap/CharacterMap.js

导入并使用TextContext组件并使用show道具显示结果,就像您在之前的组件中所做的那样:

调试教程/src/components/CharacterMap/CharacterMap.js

import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { TextContext } from '../App/App'; export default function CharacterMap({ show }) { const text = useContext(TextContext); if(!show) { return null; } return( Character Map: {text.length} ) } CharacterMap.proTypes = { show: PropTypes.bool.isRequired }

这个组件需要一个稍微复杂的函数来为每个字母创建频率图。您需要遍历每个字符并在每次重复时增加一个值。然后,您需要获取该数据并对其进行排序,以便最常见的字母位于列表顶部。

为此,请添加以下突出显示的代码:

调试教程/src/components/CharacterMap/CharacterMap.js

import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { TextContext } from '../App/App'; function itemize(text){ const letters = text.split('') .filter(l => l !== ' ') .reduce((collection, item) => { const letter = item.toLowerCase(); return { ...collection, [letter]: (collection[letter] || 0) + 1 } }, {}) return Object.entries(letters) .sort((a, b) => b[1] - a[1]); } export default function CharacterMap({ show }) { const text = useContext(TextContext); if(!show) { return null; } return( Character Map: {itemize(text).map(character => ( {character[0]}: {character[1]} ))} ) } CharacterMap.proTypes = { show: PropTypes.bool.isRequired }

在此代码中,您创建了一个名为itemize的函数,该函数使用split()字符串方法将文本拆分为数组个字符。然后你reduce通过添加字符然后增加每个后续字符的计数来将数组添加到对象中。最后,使用Object.entries和[sort](https://www.digitalocean.com/community/tutorials/how-to-use-array-methods-in-javascript-mutator-methods#sort()将对象转换为对数组,将最常用的字符放在顶部。

创建函数后,在render方法中将文本传递给函数,并在结果上传递map以在中显示字符(数组值[0])和计数(数组值[1])。

保存并关闭文件。此功能将使您有机会在下一节中探索 React 开发者工具的一些性能特性。

接下来,将新组件添加到TextInformation并查看 React Developer Tools 中的值。

打开TextInformation.js:

nano src/components/TextInformation/TextInformation.js

导入并渲染新组件:

调试教程/src/components/TextInformation/TextInformation.js

import React, { useReducer } from 'react'; import CharacterCount from '../CharacterCount/CharacterCount'; import CharacterMap from '../CharacterMap/CharacterMap'; import WordCount from '../WordCount/WordCount'; const reducer = (state, action) => { return { ...state, [action]: !state[action] } } export default function TextInformation() { const [tabs, toggleTabs] = useReducer(reducer, { characterCount: true, wordCount: true, characterMap: true }); return( toggleTabs('characterCount')}>Character Count toggleTabs('wordCount')}>Word Count toggleTabs('characterMap')}>Character Map ) }

保存并关闭文件。当你这样做时,浏览器会刷新,如果你添加一些数据,你会在新组件中找到字符频率分析:

React 开发者工具中的 CharacterMap 组件

在本节中,您使用了 React 开发者工具来探索组件树。您还学习了如何查看每个组件的实时道具以及如何使用开发人员工具手动更改道具。最后,您通过输入查看了组件更改的上下文。

在下一节中,您将使用 React Developer Tools Profiler 选项卡来识别具有较长渲染时间的组件。

第 3 步 - 跨交互跟踪组件渲染

在这一步中,您将在使用示例应用程序时使用 React Developer Tools 分析器来跟踪组件渲染和重新渲染。您将导航 flamegraphs 或应用程序相关优化指标的可视化,并使用这些信息来识别低效组件、减少渲染时间并提高应用程序速度。

到此步骤结束时,您将了解如何识别在用户交互期间呈现的组件以及如何组合组件以减少低效呈现。

查看组件如何相互更改的一种快速方法是在重新渲染组件时启用突出显示。这将使您直观地了解组件如何响应不断变化的数据。

在 React 开发者工具中,点击 Settings 图标。它看起来像一个齿轮:

设置图标

然后选择 General 下的选项,上面写着 Highlight updates when components render。

突出显示更改

当您进行任何更改时,React 开发人员工具将突出显示重新渲染的组件。例如,当您更改输入时,每个组件都会重新渲染,因为数据存储在根级别的 Hook 中,并且每次更改都会重新渲染整个组件树。

注意组件周围的突出显示,包括根组件周围的屏幕顶部:

突出显示文本

将其与单击其中一个按钮以切换数据时组件重新呈现的方式进行比较。如果单击其中一个按钮,则TextInformation下的组件将重新渲染,但不会重新渲染根组件:

仅重新渲染较低的组件

显示重新渲染将使您快速了解组件之间的关系,但它不会为您提供大量数据来分析特定组件。为了获得更多的洞察力,让我们看看探查器工具。

分析器工具旨在帮助您精确测量每个组件渲染所需的时间。这可以帮助您识别可能缓慢或过程密集的组件。

重新打开设置并取消选中组件渲染时突出显示更新的框。然后单击控制台中的 Profiler 选项卡。

要使用分析器,请单击屏幕左侧的蓝色圆圈开始录制,并在完成后再次单击它:

开始分析

当您停止录制时,您会发现组件更改的图表,包括每个项目的渲染时间。

为了更好地了解组件的相对效率,请在维基百科页面中粘贴 Creative Commons。这段文本足够长,可以给出有趣的结果,但又不会太大,以至于会导致应用程序崩溃。

粘贴文本后,启动分析器,然后对输入进行小幅更改。在组件完成重新渲染后停止分析。会有很长的停顿,因为应用程序正在处理长时间的重新渲染:

添加带有大量文本的更改

当您结束录制时,React Developer Tools 将创建一个火焰图,显示重新渲染的每个组件以及重新渲染每个组件所需的时间。

在这种情况下,“更改”一词的每次按键都会导致重新渲染。更重要的是,它显示了每次渲染需要多长时间以及为什么会有很长的延迟。组件App、TextContext.Provider和TextInformation需要大约 0.2 毫秒才能重新呈现。但是由于itemize函数中的复杂数据解析,CharacterMap组件每次击键需要大约 1 秒的时间来重新渲染。

在显示中,每个黄色条都是一个新的击键。您可以通过单击每个栏一次重播一个序列。请注意,渲染时间略有不同,但CharacterMap一直很慢:

看火焰图

您可以通过选择设置的 Profiler 部分下的选项 Record why each component 在分析时呈现。 来获取更多信息。

Profiler 选项卡的“记录原因”选项

尝试切换 Word Count 组件并注意更改需要多长时间。即使您没有更改文本内容,应用程序仍然滞后:

字数切换火焰图

现在,当您将光标悬停在组件上时,您会发现它包含组件重新渲染的原因。在这种情况下,组件更改的原因是渲染的父组件。这是CharacterMap组件的问题。CharacterMap每次父项更改时都会进行昂贵的计算,即使道具和上下文没有更改。也就是说,即使数据与之前的渲染相同,它也会重新计算数据。

单击 Ranked 选项卡,您会发现CharacterMap与所有其他组件相比需要多长时间:

排名标签

React 开发人员工具帮助隔离了一个问题:CharacterMap组件在任何父组件更改时重新渲染并执行昂贵的计算。

有多种方法可以解决这个问题,但它们都涉及通过_memoization_进行的某种缓存,这是一个记住已经计算的数据而不是重新计算的过程。您可以使用lodash/memoize或memoize-one之类的库来缓存itemize函数的结果,也可以使用内置的 Reactmemo函数来记忆整个组件。

如果您使用 Reactmemo,该函数只会在道具或上下文发生变化时重新渲染。在这种情况下,您将使用 Reactmemo。通常,您应该首先记住数据本身,因为它是一个更加孤立的案例,但是如果您记住整个组件,React 开发人员工具中有一些有趣的变化,所以您将在本教程中使用该方法。

打开CharacterMap.js:

nano src/components/CharacterMap/CharacterMap.js

从 React 导入memo,然后将整个函数传递给memo函数:

调试教程/src/components/CharacterMap/CharacterMap.js

import React, { memo, useContext } from 'react'; import PropTypes from 'prop-types'; import { TextContext } from '../App/App'; ... function CharacterMap({ show }) { const text = useContext(TextContext); if(!show) { return null; } return( Character Map: {itemize(text).map(character => ( {character[0]}: {character[1]} ))} ) } CharacterMap.proTypes = { show: PropTypes.bool.isRequired } export default memo(CharacterMap);

您将export default行移动到代码的末尾,以便在导出之前将组件传递给memo。之后,React 会在重新渲染之前比较 props。

保存并关闭文件。浏览器将重新加载,当您切换WordCount时,组件将更新得更快。这一次,CharacterMap不会重新渲染。相反,在 React 开发者工具中,你会看到一个灰色的矩形显示重新渲染被阻止。

React 开发者工具显示 CharacterMap 没有重新渲染

如果您查看 Ranked 选项卡,您会发现CharacterCount和WordCount都重新渲染,但原因不同。由于CharacterCount没有被记忆,它重新渲染,因为父级改变了。WordCount重新渲染是因为道具改变了。即使它被包裹在memo中,它仍然会重新渲染。

记忆应用的排名视图

注意: 记忆是有帮助的,但你应该只在你有明显的性能问题时才使用它,就像你在这种情况下所做的那样。否则,它可能会产生性能问题:React 每次重新渲染时都必须检查 props,这可能会导致较小组件的延迟。

在此步骤中,您使用分析器来识别重新渲染和组件重新渲染。您还使用火焰图和排名图来识别重新渲染缓慢的组件,然后使用memo函数来防止在道具或上下文没有更改时重新渲染。

结论

React Developer Tools 浏览器扩展为您提供了一组强大的实用程序来探索您的应用程序中的组件。使用这些工具,您将能够使用真实数据探索组件的状态并识别错误,而无需控制台语句或调试器。您还可以使用分析器来探索组件之间的交互方式,从而使您能够识别和优化在整个应用程序中呈现缓慢的组件。这些工具是开发过程的关键部分,让您有机会将组件作为应用程序的一部分进行探索,而不仅仅是作为静态代码。

如果您想了解有关调试 JavaScript 的更多信息,请参阅我们的文章How To Debug Node.js with the Built-In Debugger 和 Chrome DevTools。如需更多 React 教程,请查看我们的React 主题页面,或返回如何在 React.js 系列页面中编码。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有